package com.example.ymm.modules1.socket;

import com.alibaba.fastjson.JSONObject;
import com.example.ymm.modules1.entity.hl.ex.ExPaper;
import com.example.ymm.modules1.entity.hl.ex.ExPublishGroup;
import com.example.ymm.modules1.entity.hl.ex.ExPublishPaper;
import com.example.ymm.modules1.service.dto.heng.ex.UserAnserDto;
import com.example.ymm.modules1.service.dto.socket.MySocketInfo;
import com.example.ymm.modules1.service.dto.socket.SocketManager;
import com.example.ymm.modules1.service.hl.ex.ExPaperService;
import com.example.ymm.modules1.service.hl.ex.ExPublishPaperService;
import com.example.ymm.util.JsonUtil;
import com.example.ymm.util.SpringTool;
import com.example.ymm.util.UtilValidate;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.channels.CompletionHandler;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/ws/exSocket/{userName}/{publishPaperId}/{type}")
@Slf4j
@Component
public class UserExWebSocket  {


    private static final Logger LOGGER = LoggerFactory.getLogger(DataSource.class);
    //               userName  MySocketInfo
    public static Map<String, MySocketInfo> userNameMap = new HashMap<String, MySocketInfo>();
    //               MySocketInfo  publishPaperId
    public static Map<MySocketInfo, String> paperMap = new HashMap<MySocketInfo, String>();
    //                 id   Session
    public static Map<String,MySocketInfo> sessionMap = new HashMap<String,MySocketInfo>();

    private static int onlineCount = 0;
    private static CopyOnWriteArraySet<UserExWebSocket> webSocketSet = new CopyOnWriteArraySet<UserExWebSocket>();
    private  ExPaperService exPaperService;
    private Session session;
    private static String JOIN_METHOD = "join";//加入考试

    private static String PAPER_INFO_METHOD = "paper_info";//获取试卷信息


    public UserExWebSocket(){


    }

    public UserExWebSocket(ExPaperService exPaperService) {
        this.exPaperService = exPaperService;
    }
//        private  String SOCKET_INFO_METHOD="HeartBeat";


    @OnOpen
    public void onOpen(Session session, @PathParam("userName") String userName, @PathParam("publishPaperId") String publishPaperId, @PathParam("type") String type) {
        this.session = session;
        webSocketSet.add(this);
        System.out.println("---onOpen:"+userName);
//        System.out.println("--publishPaperId:" + publishPaperId);
        try {
//            System.out.println("--连接成功!:" + userName);
            SocketManager socketManager = new SocketManager();
            socketManager.setMessage("socket链接打开成功！");
            socketManager.setId(session.getId());
            socketManager.setType(SocketManager.CONNECT_SOCKET);
            socketManager.setPublishPaperId(publishPaperId);
            ExPublishPaperService exPublishPaperService=SpringTool.getApplicationContext().getBean(ExPublishPaperService.class);
            this.exPaperService = SpringTool.getApplicationContext().getBean(ExPaperService.class);

            ExPublishPaper publishPaper=null;
            if("user_paper".equals(type)){
//                publishPaper=exPublishPaperService.getUserPaper(userName,publishPaperId);
            }else{
                publishPaper = exPublishPaperService.getSamplePaper(publishPaperId);
                if(UtilValidate.isNotEmpty(publishPaper.getPaperId())){
                    ExPaper exPaper = exPaperService.getById(publishPaper.getPaperId());
                    if(UtilValidate.isNotEmpty(exPaper)){
                        publishPaper.setRuleType(exPaper.getRuleType());
                        if(exPaper.getRuleType()==0){
                            publishPaper.setStatus(1);
                        }
                    }
                }

            }
//            JSONObject jsonObject = JsonUtil.parseEntityToJson(publishPaper);
            socketManager.setPublishPaper(publishPaper);
            String string = JsonUtil.parseEntityToJson(socketManager).toString();
            this.sendMessage(string);
            MySocketInfo mySocketInfo = new MySocketInfo();
            mySocketInfo.setSession(session);
            mySocketInfo.setType(publishPaperId);
            mySocketInfo.setUserName(userName);
            mySocketInfo.setPublishPaperId(publishPaperId);
//            mySocketInfo.setType(object.getString("method"));
            MySocketInfo mySocketInfo1 = userNameMap.get(userName);
            if(UtilValidate.isNotEmpty(mySocketInfo1)){
                try{
                    webSocketSet.remove(mySocketInfo1.getSession());
                    sessionMap.remove(mySocketInfo1.getSession().getId());
                    paperMap.remove(mySocketInfo1);
                } catch (Exception e) {
                    log.error("--加入时剔除异常 session:"+e.getMessage());
                }

            }else{
                webSocketSet.add(this);
            }
            userNameMap.put(userName, mySocketInfo);
            sessionMap.put(session.getId(), mySocketInfo);
            paperMap.put(mySocketInfo,publishPaperId);
        } catch (Exception e) {
            LOGGER.error("socket connect error!" + e.getMessage());
            log.error("add message err:", e);
        }

    }

    @OnClose
    public void onClose() {
        try {

//            System.out.println(webSocketSet+":"+sessionMap+":"+userNameMap);
            MySocketInfo mySocketInfo = sessionMap.get(this.session.getId());
            System.out.println("---onClose:");
            webSocketSet.remove(this);
            if(UtilValidate.isNotEmpty(mySocketInfo)){
                System.out.println("--onClose:"+mySocketInfo.getUserName());
                userNameMap.remove(mySocketInfo.getUserName());
                paperMap.remove(mySocketInfo);
            }

            sessionMap.remove(this.session.getId());
            subOnlineCount();

        } catch (Exception e) {
            log.error("add message err:", e);
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            JSONObject object = JSONObject.parseObject(message);
            System.out.println("--接收数据:" + object);
            String publishPaperId = object.getString("publishPaperId");
            MySocketInfo mySocketInfo = sessionMap.get(session.getId());

            //客户获取试卷信息 详细
            if (PAPER_INFO_METHOD.equals(object.getString("method"))) {
             //   PushBusiness pushBusiness = new PushBusiness("ask:" + DateKit.getStringNowTime(), PushBusiness.ASK, "");
                SocketManager socketManager = new SocketManager();
                socketManager.setMessage("试卷信息获取成功！");
                socketManager.setId(session.getId());
                socketManager.setType(SocketManager.get_paper);
                socketManager.setPublishPaperId(publishPaperId);
                ExPublishPaperService exPublishPaperService=SpringTool.getApplicationContext().getBean(ExPublishPaperService.class);
                ExPublishPaper exPublishPaper=new ExPublishPaper();
                exPublishPaper.setPublishPaperId(publishPaperId);
                ExPublishPaper publishPaper = exPublishPaperService.getUserPaper(mySocketInfo.getUserName(),publishPaperId);
                socketManager.setPublishPaper(publishPaper);
                JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
                this.sendMessage(jsonObject.toString(),session);
            }
            //进入考场
            if (JOIN_METHOD.equals(object.getString("method"))) {
                ExPublishPaperService exPublishPaperService=SpringTool.getApplicationContext().getBean(ExPublishPaperService.class);
                exPublishPaperService.userJoinPaper(mySocketInfo.getUserName(), publishPaperId);
                SocketManager socketManager = new SocketManager();
                socketManager.setMessage("加入考试成功！");
                socketManager.setId(session.getId());
                socketManager.setType(SocketManager.JOIN);
                socketManager.setPublishPaperId(publishPaperId);
                JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
                this.sendMessage(jsonObject.toString(),session);
            }
            //系统强制交卷
//            if ("user_sub".equals(object.getString("method"))) {
//                try {
//                    ExPublishPaper publishPaper = JSONObject.parseObject(object.getJSONObject("publishPaper").toString(), ExPublishPaper.class);
//                    ExPublishPaperService exPublishPaperService=SpringTool.getApplicationContext().getBean(ExPublishPaperService.class);
//                    System.out.println("---用户交卷:"+object.getJSONObject("publishPaper"));
//                    exPublishPaperService.sysSubmitPaper(publishPaper,mySocketInfo.getUserName());
////                    publishPaper=exPublishPaperService.getUserPaper(mySocketInfo.getUserName(),publishPaper.getPublishPaperId());
////                    this.sendToUserPaper(publishPaper,mySocketInfo.getUserName());
//                }catch (Exception e){
//                    log.error(e.getMessage());
//                }
//
//            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            log.error("socket onMessage error!" + e.getMessage());
        }

    }


    @OnError
    public void onError(Session session, Throwable throwable) {
        // 错误处理逻辑
        //log.error("--WebSocket 错误:", throwable);


    }


    public void sendMessage(String message) throws IOException {
        try {
            this.session.getAsyncRemote().sendText(message);
        } catch (Exception e) {
            log.error("socket sendMessage error!" + e.getMessage());
            log.error("add message err:", e);
        }
    }

    public void sendMessage(String message, Session session) throws IOException {
        session.getAsyncRemote().sendText(message);
    }

    public static void sendMessage(String message, String userName) throws IOException {
        userNameMap.get(userName).getSession().getAsyncRemote().sendText(message);
    }

    /**
     * 广播开始考试
     * @param publishPaper
     */
    public static void broadcastStartPaper(ExPublishPaper publishPaper){
//        System.out.println("----sessionMap"+sessionMap);
        List<MySocketInfo> notifyAll=new ArrayList<MySocketInfo>();
        for (Map.Entry<MySocketInfo, String> entry : paperMap.entrySet()) {
            MySocketInfo info = entry.getKey();
            String id = entry.getValue();
            if(id.equals(publishPaper.getPublishPaperId())){
                notifyAll.add(info);
            }
        }
        notifyAll.forEach(session->{
            SocketManager socketManager = new SocketManager();
            socketManager.setMessage("开始考试！");
            socketManager.setId(session.getSession().getId());
            socketManager.setType(SocketManager.START);
            socketManager.setPublishPaperId(publishPaper.getPublishPaperId());
            try {
                JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
                session.getSession().getAsyncRemote().sendText(jsonObject.toString());
            } catch (Exception e) {
                log.error("通知开始考试异常 error!" + e.getMessage());
            }
        });
    }





    /**
     * 广播交卷
     * @param publishPaper
     */
    public static void broadcastSysSubmitPaper(ExPublishPaper publishPaper,Integer limitTime,String endDateTime){
        List<MySocketInfo> notifyAll=new ArrayList<MySocketInfo>();
        for (Map.Entry<MySocketInfo, String> entry : paperMap.entrySet()) {
            MySocketInfo info = entry.getKey();
            String id = entry.getValue();
            if(id.equals(publishPaper.getPublishPaperId())&&info.getSession().isOpen()){
                notifyAll.add(info);
            }
        }
        notifyAll.forEach(session->{
            SocketManager socketManager = new SocketManager();
            socketManager.setMessage("交卷");
            socketManager.setStatus(publishPaper.getStatus());
            socketManager.setId(session.getSession().getId());
            socketManager.setType(SocketManager.SYS_SUBMIT);
            socketManager.setLimitTime(limitTime);
            socketManager.setEndDateTime(endDateTime);
            socketManager.setPublishPaperId(publishPaper.getPublishPaperId());
            /**
             * 会出现
             * the remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
             */
            System.out.println("--发送交卷:isOpen:"+session.getSession().isOpen());
//            publishPaper.setGroups(null);
//            socketManager.setPublishPaper(publishPaper);
            JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
            try {
                session.getSession().getAsyncRemote().sendText(jsonObject.toString(), new SendHandler() {
                    @Override
                    public void onResult(SendResult result) {
                        System.out.println("--ok:"+result.isOK());
                        if(UtilValidate.isNotEmpty(result.getException())){
                            System.out.println("--交卷err:"+result.getException().getMessage());
                        }

                    }
                });
            } catch (Exception e) {
                log.error("发送交卷异常:"+ e.getMessage(),e);
            }


        });
    }



    /**
     * 广播排名情况
     * @param publishPaper
     */
    public static void broadcastRankPaper(ExPublishPaper publishPaper){
        List<MySocketInfo> notifyAll=new ArrayList<MySocketInfo>();
        for (Map.Entry<MySocketInfo, String> entry : paperMap.entrySet()) {
            MySocketInfo info = entry.getKey();
            String id = entry.getValue();
            if(id.equals(publishPaper.getPublishPaperId())&&info.getSession().isOpen()){
                notifyAll.add(info);
            }
        }
        notifyAll.forEach(session->{
            SocketManager socketManager = new SocketManager();
            socketManager.setMessage("排名");
            socketManager.setId(session.getSession().getId());
            socketManager.setType(SocketManager.CLOSE);

            socketManager.setPublishPaperId(publishPaper.getPublishPaperId());
            /**
             * 会出现
             * the remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
             */
            System.out.println("--发送排名:isOpen:"+session.getSession().isOpen());
//            publishPaper.setGroups(null);
//            socketManager.setPublishPaper(publishPaper);
            JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
            try {
                session.getSession().getAsyncRemote().sendText(jsonObject.toString(), new SendHandler() {
                    @Override
                    public void onResult(SendResult result) {
                        System.out.println("--ok:"+result.isOK());
                        if(UtilValidate.isNotEmpty(result.getException())){
                            System.out.println("--err:"+result.getException().getMessage());
                        }

                    }
                });
            } catch (Exception e) {
                log.error("发送排名异常:"+ e.getMessage(),e);
            }


        });
    }


    /**
     * 广播 下一个模块信息
     * @param publishPaper
     */
    public static void broadcastNextGroup(ExPublishPaper publishPaper){
        List<MySocketInfo> notifyAll=new ArrayList<MySocketInfo>();
        for (Map.Entry<MySocketInfo, String> entry : paperMap.entrySet()) {
            MySocketInfo info = entry.getKey();
            String id = entry.getValue();
            if(id.equals(publishPaper.getPublishPaperId())){
                notifyAll.add(info);
            }
        }
        notifyAll.forEach(session->{
            SocketManager socketManager = new SocketManager();
            socketManager.setMessage("下一模块");
            socketManager.setId(session.getSession().getId());
            socketManager.setType(SocketManager.NEXT_GROUP);
            socketManager.setPublishPaperId(publishPaper.getPublishPaperId());
            socketManager.setPublishPaper(publishPaper);
            try {
                JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);
                session.getSession().getAsyncRemote().sendText(jsonObject.toString());
            } catch (Exception e) {
                log.error("通知下一模块异常 error!" + e.getMessage());
            }
        });
    }



    /**
     * 告诉用户刷新考卷信息
     */
    public static void sendToUserPaper(ExPublishPaper publishPaper,String userName){

        SocketManager socketManager = new SocketManager();
        socketManager.setMessage("试卷信息");
        socketManager.setId(userNameMap.get(userName).getSession().getId());
        socketManager.setType(SocketManager.PAPER_INFO);
        socketManager.setPublishPaperId(publishPaper.getPublishPaperId());
        socketManager.setPublishPaper(publishPaper);
        JSONObject jsonObject = JsonUtil.parseEntityToJson(socketManager);

        try {
            sendMessage(jsonObject.toString(),userName);
        } catch (IOException e) {
            log.error("发送试卷信息异常:"+e.getMessage(),e);
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        onlineCount--;
    }

}
